/***
 * * PROJECT
 * *    ATaG
 * * VERSION
 * *    $Revision: 1.2 $
 * * DATE
 * *    $Date: 2007/06/09 07:15:49 $
 * * LOG
 * *    $Log: ATaGProgram.java,v $
 * *    Revision 1.2  2007/06/09 07:15:49  animesh
 * *    update after fixing all but sets and serialization.
 * *
 * *    Revision 1.11  2007/05/17 09:56:22  qunzhi
 * *    replaced generics. problem line 520 676
 * *
 * *    Revision 1.10  2007/01/29 16:27:08  lmottola
 * *    Fixed bug in casting arrays.
 * *
 * *    Revision 1.9  2007/01/29 08:06:22  animesh
 * *    tried casting the toArray of tempList, but without success.
 * *
 * *    Revision 1.8  2007/01/29 07:38:36  animesh
 * *    corrected one occurance of "sourceTask" to "targetTask".
 * *
 * *    Revision 1.7  2007/01/15 09:09:21  animesh
 * *    added function for returning scope used between T1 and T2 through D.
 * *    Also added functions to return task lists associated with a data item and vice versa.
 * *
 * *    Revision 1.6  2006/11/03 23:08:18  lmottola
 * *    Traffic application beta running.
 * *
 * *    Revision 1.5  2006/10/25 19:37:44  animesh
 * *    Moved functions from ATaGManager to this.
 * *
 * *    Revision 1.4  2006/10/21 00:17:54  animesh
 * *    no message
 * *
 * *    Revision 1.3  2006/10/19 21:21:53  lmottola
 * *    Added CVS preamble.
 * * 
 * *   ATaG (Abstract Task Graph) - Data-driven Macroprogramming for
 * *                                Sensor Networks
 * *
 * *   This program is free software; you can redistribute it and/or
 * *   modify it under the terms of the GNU General Public License
 * *   as published by the Free Software Foundation; either version 2
 * *   of the License, or (at your option) any later version.
 * *
 * *   This program is distributed in the hope that it will be useful,
 * *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 * *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * *   GNU General Public License for more details.
 * *
 * *   You should have received a copy of the GNU General Public License
 * *   along with this program; if not, you may find a copy at the FSF web
 * *   site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
 * *   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * *   Boston, MA  02111-1307, USA
 ***/

package atag.common;

//import atag.compiler.*;
import atag.runtime.NodeInfo;
import atag.runtime.ln.neighborhoodDefs.*;
import java.util.*;

/**
 * The main program node. This closely reflects the schema
 * @author Animesh
 */
public class ATaGProgram {
    
    //ArrayList<ATaGTaskDeclaration> taskList;
    //ArrayList<ATaGDataItemDeclaration> dataList;
    //ArrayList<ScopedChannel> channelList;
    Vector taskList;
    Vector dataList;
    Vector channelList;
    
    /** Creates a new instance of ATaGProgram */
    public ATaGProgram() {
        //this.taskList = new ArrayList<ATaGTaskDeclaration>();
        //this.dataList = new ArrayList<ATaGDataItemDeclaration>();
        //this.channelList = new ArrayList<ScopedChannel>();
        this.taskList = new Vector();
        this.dataList = new Vector();
        this.channelList = new Vector();
    }
    //public ArrayList<ATaGTaskDeclaration> getTaskList(){
    public Vector getTaskList(){
        return this.taskList;
    }
    //public ArrayList<ATaGDataItemDeclaration> getDataList(){
    public Vector getDataList(){
        return this.dataList;
    }
    //public ArrayList<ScopedChannel> getChannelList(){
    public Vector getChannelList(){
        return this.channelList;
    }
    
    public int numTasks(){
        return this.taskList.size();
    }
    
    public int numDataItems(){
        return this.dataList.size();
    }
    
    public int numChannels(){
        return this.channelList.size();
    }
    
    /**
     * This method looks at the created task list and data list and channel list
     * and fills in the data that could not be filled by the parser
     * like the IDs etc.
     * This of this as pass 2 of the compiler
     */
    public void sanitize() {
        
        //check if all task names are unique
        
        for (int i=0; i<this.taskList.size(); i++){
            //set its ID
            ((ATaGTaskDeclaration) this.taskList.elementAt(i)).setID(i);
            
            for(int j = i+1; j<this.taskList.size();j++){
                if(((ATaGTaskDeclaration) this.taskList.elementAt(i)).getName().equalsIgnoreCase(
                        ((ATaGTaskDeclaration) this.taskList.elementAt(j)).getName())){
                    //oops -- Names match
                    System.err.println("Both tasks " + i + " and " + j + " have " +
                            "the same name " + ((ATaGTaskDeclaration) this.taskList.elementAt(j)).getName());
                    System.exit(-4);
                }
            }
        }// all tasks now have unique IDs also :-).
        
        //check if all data names are unique
        for (int i=0; i<this.dataList.size(); i++){
            //set its ID
            ((ATaGDataItemDeclaration) this.dataList.elementAt(i)).setID(i);
            
            for(int j = i+1; j< this.dataList.size();j++){
                if(((ATaGDataItemDeclaration) this.dataList.elementAt(i)).getName().equalsIgnoreCase(
                        ((ATaGDataItemDeclaration) this.dataList.elementAt(j)).getName())){
                    //oops -- Names match
                    System.err.println("Both tasks " + i + " and " + j + " have " +
                            "the same name " + ((ATaGDataItemDeclaration) this.dataList.elementAt(j)).getName());
                    System.exit(-4);
                }
            }
        }// all data items now have unique IDs also :-).
        
        //now all tasks and data items have unique IDs
        //for each channel.
        //set the taskID and dataID [make functions for them]
        
        //for (ScopedChannel c: this.channelList){
        for (int ci =0; ci < this.channelList.size(); ci++){
            //int tID = this.taskIDFromName(c.getTaskName());
            //int dID = this.dataIDFromName(c.getDataName());
            ScopedChannel c=((ScopedChannel) this.channelList.elementAt(ci));
             if (c.isRequestResponse()){

                String taskNames[]= StringHelper.splitString(c.getTaskName(),' ');
                int reqTaskID=this.taskIDFromName(taskNames[0]);
                int resTaskID=this.taskIDFromName(taskNames[1]);
                String dataNames[]= StringHelper.splitString(c.getDataName(),' ');
                int reqdataID=this.dataIDFromName(dataNames[0]);
                int resdataID=this.dataIDFromName(dataNames[1]);

                c.setTaskID(reqTaskID);
                c.setDataID(reqdataID);

                ((ATaGTaskDeclaration) this.taskList.elementAt(reqTaskID)).
                        outDataNames().addElement(dataNames[0]);
                ((ATaGTaskDeclaration) this.taskList.elementAt(resTaskID)).
                        outDataNames().addElement(dataNames[1]);
                ((ATaGTaskDeclaration) this.taskList.elementAt(reqTaskID)).
                        outDataNames().addElement(dataNames[1]);
                ((ATaGTaskDeclaration) this.taskList.elementAt(resTaskID)).
                        outDataNames().addElement(dataNames[0]);
            }else{

                //c.setTaskID(tID);
                //c.setDataID(dID);
                int tID = this.taskIDFromName(((ScopedChannel) this.channelList.elementAt(ci)).getTaskName());
                int dID = this.dataIDFromName(((ScopedChannel) this.channelList.elementAt(ci)).getDataName());

                ((ScopedChannel) this.channelList.elementAt(ci)).setTaskID(tID);
                ((ScopedChannel) this.channelList.elementAt(ci)).setDataID(dID);

                //if (c.getDirection() == ScopedChannel.CHANNEL_TYPE_OUTPUT){
                if (((ScopedChannel) this.channelList.elementAt(ci)).getDirection() == ScopedChannel.CHANNEL_TYPE_OUTPUT){
                    //"output channel"
                    //((ATaGTaskDeclaration) this.taskList.elementAt(tID)).outDataNames().add(c.getDataName());
                    ((ATaGTaskDeclaration) this.taskList.elementAt(tID)).outDataNames().addElement(((ScopedChannel) this.channelList.elementAt(ci)).getDataName());
                }else{
                    //input channel
                    //((ATaGTaskDeclaration) this.taskList.elementAt(tID)).inDataNames().add(c.getDataName());
                    ((ATaGTaskDeclaration) this.taskList.elementAt(tID)).inDataNames().addElement(((ScopedChannel) this.channelList.elementAt(ci)).getDataName());
                }
            }
        }// all channels done
        
        //make sure each data item has only one "producer"
        //for (ATaGDataItemDeclaration d:this.dataList){
        for (int di =0; di < this.dataList.size(); di++){
            //for all channels
            boolean producerAlreadyFound = false;
            //for(ScopedChannel c:this.channelList){
            for(int ci =0; ci < this.channelList.size(); ci++){
                //if((c.getDirection() == ScopedChannel.CHANNEL_TYPE_OUTPUT) &&
                //      (c.getDataID() == d.getID())){
                if((((ScopedChannel) this.channelList.elementAt(ci)).getDirection() == ScopedChannel.CHANNEL_TYPE_OUTPUT) &&
                        (((ScopedChannel) this.channelList.elementAt(ci)).getDataID() == ((ATaGDataItemDeclaration) this.dataList.elementAt(di)).getID())){
                    if (producerAlreadyFound){
                        //print error
                        System.err.println("Oops. Data item "+ ((ATaGDataItemDeclaration) this.dataList.elementAt(di)).getName() +
                                "has two producers");
                        System.exit(-3);
                    }else{
                        producerAlreadyFound = true;
                    }
                }
            }
        }// for all data items
    }
    
    /** returns the ID of a task given only its name
     */
    private int taskIDFromName(String name)  throws NoSuchElementException {
        
        for (int i = 0; i < this.taskList.size(); i++){
            if (((ATaGTaskDeclaration) this.taskList.elementAt(i)).getName().equalsIgnoreCase(name)){
                return ((ATaGTaskDeclaration) this.taskList.elementAt(i)).getID();
            }
        }
        // basically to cause an exception if the number is still -ve
        throw new NoSuchElementException("No task with name " + name + " found");
    }
    
    /** returns the ID of a data given only its name
     */
    private int dataIDFromName(String name)  throws NoSuchElementException {
        
        for (int i = 0; i < this.dataList.size(); i++){
            if (((ATaGDataItemDeclaration) this.dataList.elementAt(i)).getName().equalsIgnoreCase(name)){
                return ((ATaGDataItemDeclaration) this.dataList.elementAt(i)).getID();
            }
        }
        // basically to cause an exception if the number is still -ve
        throw new NoSuchElementException("No data with name " + name + " found");
    }
    
    
    
    /** @returns an array of channelIDs which are the input channels attached to a data item
     * @param dataID the ID of the data
     *
     */
    public ScopedChannel[] inputChannelsD(int dataID) {
        int count = 0;
        for (int i = 0; i < channelList.size(); i++)
            if ((((ScopedChannel) channelList.elementAt(i)).getDataID() == dataID) &&
                (((ScopedChannel) channelList.elementAt(i)).getTypeInString().toUpperCase()).equals("INPUT"))
                count++;
        ScopedChannel[] returnVal = new ScopedChannel[count];
        int j = 0;
        for (int i = 0; i < channelList.size(); i++)
            if ((((ScopedChannel) channelList.elementAt(i)).getDataID() == dataID) &&
                (((ScopedChannel) channelList.elementAt(i)).getTypeInString().toUpperCase()).equals("INPUT"))
                returnVal[j++] = ((ScopedChannel) channelList.elementAt(i));
        
        return returnVal;
    }
    
    /**
     * @returns an array of channels which are the input
     * channels attached to a data item
     * @param dataID the ID of the data
     *
     */
    //public ArrayList<ScopedChannel> getInChannelListForData(int dataID) {
    public Vector getInChannelListForData(int dataID) {
        Vector retList = new Vector();
        for (int i = 0; i < channelList.size(); i++)
            if ((((ScopedChannel) channelList.elementAt(i)).getDataID() == dataID) &&
                (((ScopedChannel) channelList.elementAt(i)).getTypeInString().toUpperCase()).equals("INPUT")){
            retList.addElement(((ScopedChannel) channelList.elementAt(i)));
            }
        return retList;
    }
    
    
    
    /** @returns an array of channelIDs which are the output channels attached to a data item
     * @param dataID the ID of the data
     *
     */
    public ScopedChannel[] outputChannelsD(int dataID) {
        int count = 0;
        for (int i = 0; i < channelList.size(); i++)
            if ((((ScopedChannel) channelList.elementAt(i)).getDataID() == dataID) &&
                (((ScopedChannel) channelList.elementAt(i)).getTypeInString().toUpperCase()).equals("OUTPUT"))
                count++;
        ScopedChannel[] returnVal = new ScopedChannel[count];
        int j = 0;
        for (int i = 0; i < channelList.size(); i++)
            if ((((ScopedChannel) channelList.elementAt(i)).getDataID() == dataID) &&
                (((ScopedChannel) channelList.elementAt(i)).getTypeInString().toUpperCase()).equals("OUTPUT"))
                returnVal[j++] = ((ScopedChannel) channelList.elementAt(i));
        
        return returnVal;
    }
    
    /**
     * @returns the channel, given the task ID and the data ID
     * @param taskID the ID of the task
     * @param dataID the ID of the data
     */
    public ScopedChannel getChannelFromTaskAndData(int taskID, int dataID)
    throws NoSuchElementException {
        boolean found = false;
        ScopedChannel retChannel = null;
        //for (ScopedChannel c: this.channelList){
        for (int ci=0; ci < this.channelList.size(); ci++ ){
            //if ((c.getDataID() == dataID) && (c.getTaskID()== taskID)){
            ScopedChannel c=(ScopedChannel) this.channelList.elementAt(ci);
            if(c.isRequestResponse())
            {
                String taskNames[]= StringHelper.splitString(c.getTaskName(),' ');
                int reqTaskID=this.taskIDFromName(taskNames[0]);
                int resTaskID=this.taskIDFromName(taskNames[1]);
                String dataNames[]= StringHelper.splitString(c.getDataName(),' ');
                int reqdataID=this.dataIDFromName(dataNames[0]);
                int resdataID=this.dataIDFromName(dataNames[1]);
                if(reqTaskID==taskID || resTaskID==taskID)
                {
                    if(reqdataID==dataID || resdataID==dataID)
                    {
                        if (found == true){// this is a duplicate
                        System.err.println("There are two channels with the same Data ID " + dataID
                                + " and Task " + taskID );
                        System.exit(-4);
                        }else{// first occurance
                            retChannel = c;
                            found = true;
                        }
                    }
                }
            }else{
                if ((((ScopedChannel) this.channelList.elementAt(ci)).getDataID() == dataID) && (((ScopedChannel) this.channelList.elementAt(ci)).getTaskID()== taskID)){
                    if (found == true){// this is a duplicate
                        System.err.println("There are two channels with the same Data ID " + dataID
                                + " and Task " + taskID );
                        System.exit(-4);
                    }else{// first occurance
                        retChannel = ((ScopedChannel) this.channelList.elementAt(ci));
                        found = true;
                    }
                }
            }
        }
        if (found == false) //still not found
            throw new NoSuchElementException("No channel connecting Data ID " + dataID
                    + " and Task " + taskID + " found");
        else
            return retChannel;
        
        
    }
    
    public int[] getInDataOfTask(int taskID) {
        // go through channels and get a list
        int x = this.numDataItems();
        int[] dataArray = new int[x];
        //TODO -- not inited to zeros
        //for (ScopedChannel t_channelDecl: this.channelList) {
        for (int ci=0; ci < this.channelList.size(); ci++ ) {
            // If the input channel matches this task ID,
            // Mark the channel's data ID index as true;
            //if (t_channelDecl.isInput() && (t_channelDecl.taskID() == taskID))
            if (((ScopedChannel) this.channelList.elementAt(ci)).isInput() && (((ScopedChannel) this.channelList.elementAt(ci)).taskID() == taskID))
                dataArray[((ScopedChannel) this.channelList.elementAt(ci)).dataID()] = 1;
        }
        return dataArray;
    }
    
    //public ArrayList<ATaGDataItemDeclaration> getInDataListOfTask(int taskID) {
    public Vector getInDataListOfTask(int taskID) {
        // go through channels and get a list
        //ArrayList dataArray = new ArrayList<ATaGDataItemDeclaration>();
        Vector dataArray = new Vector();
        //for (ScopedChannel t_channelDecl: this.channelList) {
        for (int ci=0; ci < this.channelList.size(); ci++ ) {
            // If the input channel matches this task ID,
            // add the dataItem to the list
            //if (t_channelDecl.isInput() && (t_channelDecl.taskID() == taskID))
            if (((ScopedChannel) this.channelList.elementAt(ci)).isInput() && (((ScopedChannel) this.channelList.elementAt(ci)).taskID() == taskID))
                dataArray.addElement(this.dataList.elementAt(((ScopedChannel) this.channelList.elementAt(ci)).dataID()));
        }
        return dataArray;
    }
    
    //public ArrayList<ATaGDataItemDeclaration> getOutDataListOfTask(int taskID) {
    public Vector getOutDataListOfTask(int taskID) {
        // go through channels and get a list
        //ArrayList dataArray = new ArrayList<ATaGDataItemDeclaration>();
        Vector dataArray = new Vector();
        //for (ScopedChannel t_channelDecl: this.channelList) {
        for (int ci=0; ci < this.channelList.size(); ci++ ) {
            // If the input channel matches this task ID,
            // Mark the channel's data ID index as true;
            //if (t_channelDecl.isOutput() && (t_channelDecl.taskID() == taskID))
            if (((ScopedChannel) this.channelList.elementAt(ci)).isOutput() && (((ScopedChannel) this.channelList.elementAt(ci)).taskID() == taskID))
                dataArray.addElement(this.dataList.elementAt(((ScopedChannel) this.channelList.elementAt(ci)).dataID()));
        }
        return dataArray;
    }
    
    /*
     * @ return a Boolean Array indicating which of the tasks have this data item as one of its inputs.
     */
    public int[] getOutTasksOfData(int dataID) {
        // go through channels and get a list
        int x = this.numTasks();
        int[] taskArray = new int[x];
        //TODO -- not inited to zeros
        //for (ScopedChannel t_channelDecl: this.channelList) {
        for (int ci=0; ci < this.channelList.size(); ci++ ) {
            // If the input channel source matches this data ID,
            // Mark the input channel's task ID index as true;
            //if (t_channelDecl.isInput() && (t_channelDecl.dataID() == dataID))
            if (((ScopedChannel) this.channelList.elementAt(ci)).isInput() && (((ScopedChannel) this.channelList.elementAt(ci)).dataID() == dataID))
                taskArray[((ScopedChannel) this.channelList.elementAt(ci)).taskID()] = 1;
            else if(((ScopedChannel) this.channelList.elementAt(ci)).isRequestResponse())
            {
                ScopedChannel c=(ScopedChannel) this.channelList.elementAt(ci);
                String taskNames[]= StringHelper.splitString(c.getTaskName(),' ');
                int reqTaskID=this.taskIDFromName(taskNames[0]);
                int resTaskID=this.taskIDFromName(taskNames[1]);
                String dataNames[]= StringHelper.splitString(c.getDataName(),' ');
                int reqdataID=this.dataIDFromName(dataNames[0]);
                int resdataID=this.dataIDFromName(dataNames[1]);
                if(reqdataID==dataID)
                {
                    taskArray[resTaskID] = 1;
                }
                else if(resdataID==dataID)
                {
                     taskArray[reqTaskID] = 1;
                }

            }
        }
        return taskArray;
    }
    
    //public ArrayList<ATaGTaskDeclaration> getOutTasksListOfData(int dataID) {
    public Vector getOutTasksListOfData(int dataID) {
        // go through channels and get a list
        //ArrayList taskArray = new ArrayList<ATaGTaskDeclaration>();
        Vector taskArray = new Vector();
        //for (ScopedChannel t_channelDecl: this.channelList) {
        for (int ci=0; ci < this.channelList.size(); ci++ ) {
            // If the input channel source matches this data ID,
            // Mark the input channel's task ID index as true;
            //if (t_channelDecl.isInput() && (t_channelDecl.dataID() == dataID))
            if (((ScopedChannel) this.channelList.elementAt(ci)).isInput() && (((ScopedChannel) this.channelList.elementAt(ci)).dataID() == dataID))
                //insert relevant task to the array
                taskArray.addElement(this.taskList.elementAt(((ScopedChannel) this.channelList.elementAt(ci)).taskID()));
            else if(((ScopedChannel) this.channelList.elementAt(ci)).isRequestResponse())
            {
                ScopedChannel c=(ScopedChannel) this.channelList.elementAt(ci);
                String taskNames[]= StringHelper.splitString(c.getTaskName(),' ');
                int reqTaskID=this.taskIDFromName(taskNames[0]);
                int resTaskID=this.taskIDFromName(taskNames[1]);
                String dataNames[]= StringHelper.splitString(c.getDataName(),' ');
                int reqdataID=this.dataIDFromName(dataNames[0]);
                int resdataID=this.dataIDFromName(dataNames[1]);
                if(reqdataID==dataID)
                {
                    taskArray.addElement(this.taskList.elementAt(resTaskID));
                }
                else if(resdataID==dataID)
                {
                     taskArray.addElement(this.taskList.elementAt(reqTaskID));
                }

            }
        }
        return taskArray;
    }
    
    /**
     *
     *
     * @param taskID the ID of task that produces the data
     * @param dataID the ID of the data item
     * @param nInfo the nodeInfo for the node asking for the information
     * @param targetTask is the targetTask
     * @returns an LNScope, representing the output channel from source to destination
     */
    public Neighborhood getLNScopeForData(int taskID, int dataID, NodeInfo nInfo,
            ATaGTaskDeclaration targetTask) {
        ATaGDataItemDeclaration d = (ATaGDataItemDeclaration) this.dataList.elementAt(dataID);
        
        ATaGTaskDeclaration sourceTask = (ATaGTaskDeclaration) this.taskList.elementAt(taskID);
        ScopedChannel outChannel = this.getChannelFromTaskAndData(taskID, dataID);
        
        
        
        //ArrayList<LNPredicate> tempList = new ArrayList<LNPredicate>();
        Vector tempList = new Vector();
        // first add condition that target is running particular task
        Predicate targetTaskInstantiated = new StringSetMembershipPredicate(
                String.valueOf(targetTask.getID()),
                StringSetMembershipPredicate.IS_IN,
                NodeInfo.ASSIGNED_TASK_ATTR_NAME);
        tempList.addElement(targetTaskInstantiated);
        
        // then add the condition obtained from output channel
        String outputInterest = outChannel.getInterest();
        //the if below should be a case/switch ideally - Animesh
        if (outputInterest.equalsIgnoreCase("none")){
            //do nothing. Nothing to add
        }else if (outputInterest.equalsIgnoreCase("region-hops")){
            //create a hop thing
            String regionLabel = outChannel.getInterestLabel();
            int regionRange = Integer.parseInt(outChannel.getInterestParam());
            int myRegionID =
                    ((Integer) nInfo.getAttributeByName(regionLabel)).intValue();
            
            Predicate regionHopPredicate = new IntegerRangePredicate(regionLabel,
                    myRegionID - regionRange, myRegionID + regionRange);
            
            tempList.addElement(regionHopPredicate);
            
        }else if (outputInterest.equalsIgnoreCase("domain")){
            //handle domain
            int instType = sourceTask.getLocation()[0];
            
            switch(instType){
                case ATaGTaskDeclaration.INSTANTIATION_PARTITION_PER_INSTANCE:
                    // if task is "partition-per-instance, get partition name"
                    String regionLabel = sourceTask.getMyRegionName();
                    int myRegionID =
                            ((Integer) nInfo.getAttributeByName(regionLabel)).intValue();
                    
                    Predicate domainPredicate = new IntegerSimplePredicate(regionLabel,
                            IntegerSimplePredicate.EQUAL, myRegionID);
                    tempList.addElement(domainPredicate);
                    break;
                default:
                    //fail
                    System.err.println("Task " + sourceTask.getName() + "is attached" +
                            "to a domain channel but has incompatible instantiation type"
                            + sourceTask.getInstType());
                    System.exit(-1);
            }//end switch
        }// end domain stuff
        
        // then add the condition obtained from input channel
        //TODO -- the code below is repeated. Make a function out of it
        ScopedChannel inChannel = this.getChannelFromTaskAndData(targetTask.getID(), dataID);
        String inputInterest = inChannel.getInterest();
        //the if below should be a case/switch ideally - Animesh
        if (inputInterest.equalsIgnoreCase("none")){
            //do nothing. Nothing to add
        }else if (inputInterest.equalsIgnoreCase("region-hops")){
            //create a hop thing
            String regionLabel = inChannel.getInterestLabel();
            int regionRange = Integer.parseInt(inChannel.getInterestParam());
            int myRegionID =
                    ((Integer) nInfo.getAttributeByName(regionLabel)).intValue();
            
            Predicate regionHopPredicate = new IntegerRangePredicate(regionLabel,
                    myRegionID - regionRange, myRegionID + regionRange);
            
            tempList.addElement(regionHopPredicate);
        }else if (inputInterest.equalsIgnoreCase("domain")){
            //handle domain
            int instType = targetTask.getLocation()[0];
            
            switch(instType){
                case ATaGTaskDeclaration.INSTANTIATION_PARTITION_PER_INSTANCE:
                    String regionLabel = targetTask.getMyRegionName();
                    // if task is "partition-per-instance, get partition name"
                    int myRegionID =
                            ((Integer) nInfo.getAttributeByName(regionLabel)).intValue();
                    
                    Predicate domainPredicate = new IntegerSimplePredicate(regionLabel,
                            IntegerSimplePredicate.EQUAL, myRegionID);
                    tempList.addElement(domainPredicate);
                    break;
                default:
                    //fail
                    System.err.println("Task " + targetTask.getName() + "is attached" +
                            "to a domain channel but has incompatible instantiation type"
                            + sourceTask.getInstType());
                    System.exit(-1);
            }//end switch
        }// end domain stuff
        
        // finally, convert to LNScope[] and feed to conjunctivescope
//        LNPredicate[] retPredicate = ((LNPredicate[]) tempList.toArray(new LNPredicate[]{}));
        
          Predicate[] retPredicate = new Predicate[tempList.size()];
            for(int i=0;i<tempList.size();i++)
              retPredicate[i] = (Predicate) tempList.elementAt(i);

        
        // insert the conjunctivescope to the bigger array
        Neighborhood retScope = new ConjunctiveNeighborhood(retPredicate);
        
        return retScope;
    }
    
    //public ArrayList<ATaGTaskDeclaration> getFeederTasks(ATaGTaskDeclaration at){
    public Vector getFeederTasks(ATaGTaskDeclaration at){
        //TODO -- improve
        //simple method - do exhaustive search over all tasks - O(n)
        //more complex method, have reverse pointers - O(k)
        //
        
        //ArrayList<ATaGTaskDeclaration> retArr = new ArrayList();
        Vector retArr = new Vector();
        
        //for (ATaGTaskDeclaration testTask : this.taskList){
        for (int ti =0; ti < this.taskList.size(); ti++){
            //for each data produced by this task
            //for(ATaGDataItemDeclaration testData:
                //getOutDataListOfTask(testTask.getID())){
            Vector tempDataList = getOutDataListOfTask(((ATaGTaskDeclaration) this.taskList.elementAt(ti)).getID());
            for(int di =0; di < tempDataList.size(); di++ ){
                    //for each task consuming this data item
                    //for (ATaGTaskDeclaration testTask2 :
                        //this.getOutTasksListOfData(testData.getID())){
                    Vector tempTaskList = this.getOutTasksListOfData(((ATaGDataItemDeclaration) tempDataList.elementAt(di)).getID());
                    for (int ti2=0; ti2 < tempTaskList.size(); ti2++ ){
                            //if at is a "consumer" of this data item
                            //if (testTask2.getID() == at.getID()){
                            if (((ATaGTaskDeclaration) tempTaskList.elementAt(ti2)).getID() == at.getID()){
                                //add to list. Don't look at other tasks
                                //retArr.add(testTask2);
                                retArr.addElement(((ATaGTaskDeclaration) tempTaskList.elementAt(ti2)));
                                break;
                            }
                        }
                }
        }
        return retArr;
    }

    /**
     *
     *
     * @param taskID the ID of task that produces the data
     * @param dataID the ID of the data item
     * @param targetTask is the targetTask
     * @returns an LNScope, representing the output channel from source to destination
     */
    public Neighborhood getLNScopeEdgeForCATaG(int sourceTaskID, int dataID,
            ATaGTaskDeclaration targetTask) {
        
        ATaGDataItemDeclaration d = (ATaGDataItemDeclaration) this.dataList.elementAt(dataID);
        
        ATaGTaskDeclaration sourceTask = (ATaGTaskDeclaration) this.taskList.elementAt(sourceTaskID);
        ScopedChannel outChannel = this.getChannelFromTaskAndData(sourceTaskID, dataID);
        
        
        
        //ArrayList<LNPredicate> tempList = new ArrayList<LNPredicate>();
        Vector tempList = new Vector();
        // first add condition that target is running particular task
        /* removed since this is not needed for edges in CATaG
        LNPredicate targetTaskInstantiated = new SetMembershipPredicate(
                new Integer(targetTask.getID()),
                SetMembershipPredicate.IS_IN,
                NodeInfo.ASSIGNED_TASK_ATTR_NAME);
        tempList.add(targetTaskInstantiated);
        */
        
        // then add the condition obtained from output channel
        String outputInterest = outChannel.getInterest();
        //the if below should be a case/switch ideally - Animesh
        if (outputInterest.equalsIgnoreCase("none")){
            //do nothing. Nothing to add
        }else if (outputInterest.equalsIgnoreCase("region-hops")){
            //create a hop thing
            String regionLabel = outChannel.getInterestLabel();
            int regionRange = Integer.parseInt(outChannel.getInterestParam());
            
            //note that we are setting the regionID to 0 - this is a special ID
            int myRegionID = 0;
            
            Predicate regionHopPredicate = new IntegerRangePredicate(regionLabel,
                    myRegionID - regionRange, myRegionID + regionRange);
            
            tempList.addElement(regionHopPredicate);
            
        }else if (outputInterest.equalsIgnoreCase("domain")){
            //handle domain
            int instType = sourceTask.getLocation()[0];
            
            switch(instType){
                case ATaGTaskDeclaration.INSTANTIATION_PARTITION_PER_INSTANCE:
                    // if task is "partition-per-instance, get partition name"
                    String regionLabel = sourceTask.getMyRegionName();
                    //note that we are setting the regionID to 0 - this is a special ID
                    int myRegionID = 0;
                    
                    Predicate domainPredicate = new IntegerSimplePredicate(regionLabel,
                            IntegerSimplePredicate.EQUAL, myRegionID);
                    tempList.addElement(domainPredicate);
                    break;
                default:
                    //fail
                    System.err.println("Task " + sourceTask.getName() + "is attached" +
                            "to a domain channel but has incompatible instantiation type"
                            + sourceTask.getInstType());
                    System.exit(-1);
            }//end switch
        }// end domain stuff
        
        // then add the condition obtained from input channel
        //TODO -- the code below is repeated. Make a function out of it
        ScopedChannel inChannel = this.getChannelFromTaskAndData(targetTask.getID(), dataID);
        String inputInterest = inChannel.getInterest();
        //the if below should be a case/switch ideally - Animesh
        if (inputInterest.equalsIgnoreCase("none")){
            //do nothing. Nothing to add
        }else if (inputInterest.equalsIgnoreCase("region-hops")){
            //create a hop thing
            String regionLabel = inChannel.getInterestLabel();
            int regionRange = Integer.parseInt(inChannel.getInterestParam());
            //note that we are setting the regionID to 0 - this is a special ID
            int myRegionID = 0;
            
            Predicate regionHopPredicate = new IntegerRangePredicate(regionLabel,
                    myRegionID - regionRange, myRegionID + regionRange);
            
            tempList.addElement(regionHopPredicate);
        }else if (inputInterest.equalsIgnoreCase("domain")){
            //handle domain
            int instType = targetTask.getLocation()[0];
            
            switch(instType){
                case ATaGTaskDeclaration.INSTANTIATION_PARTITION_PER_INSTANCE:
                    String regionLabel = targetTask.getMyRegionName();
                    // if task is "partition-per-instance, get partition name"
                    //note that we are setting the regionID to 0 - this is a special ID
                    int myRegionID = 0;
                    
                    Predicate domainPredicate = new IntegerSimplePredicate(regionLabel,
                            IntegerSimplePredicate.EQUAL, myRegionID);
                    tempList.addElement(domainPredicate);
                    break;
                default:
                    //fail
                    System.err.println("Task " + targetTask.getName() + "is attached" +
                            "to a domain channel but has incompatible instantiation type"
                            + sourceTask.getInstType());
                    System.exit(-1);
            }//end switch
        }// end domain stuff
        
        // finally, convert to LNScope[] and feed to conjunctivescope
        //LNPredicate[] retPredicate = ((LNPredicate[]) tempList.toArray(new LNPredicate[]{}));
        Predicate[] retPredicate = new Predicate[tempList.size()];
        for(int i=0;i<tempList.size();i++)
              retPredicate[i] = (Predicate) tempList.elementAt(i);
        
        // insert the conjunctivescope to the bigger array
        Neighborhood retScope = new ConjunctiveNeighborhood(retPredicate);
        
        return retScope;
    }    
    
}
